// Eternal Lands Bot
// Copyright (C) 2006  Artem Makhutov
// artem@makhutov.org
// 
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

using System;
using System.Collections;

namespace cs_elbot
{
	/// <summary>
	/// description of TradeHandler.
	/// </summary>
	public class TradeHandler
	{
		private TCPWrapper TheTCPWrapper;
		private BasicCommunication.MessageParser TheMessageParser;
		private Logger TheLogger;
		private MySqlManager TheMySqlManager;
		private Inventory TheInventory;
        private AdvancedCommunication.ActorHandler TheActorHandler;
        private Storage TheStorage;

		private int TradeTimeElapsed = 0;
		public System.Timers.Timer TradeTimer = new System.Timers.Timer();
		
		private int AcceptStateMe = 0;
		private int AcceptStatePartner = 0;
		
		private int MyMoneySlotID = 0;
		private byte MyMoneyOnTradeSlotID = 0;
		private uint MyMoneyAmount = 0;
		private uint MyMoneyOnTrade = 0;
		private byte GettingTradListItemnameID = 255;
		
		private System.Collections.ArrayList InventorySnapshop = new System.Collections.ArrayList();
		private System.Collections.ArrayList InventorySnapshopLoging = new System.Collections.ArrayList();

        private System.Collections.ArrayList StorageSnapshot = new System.Collections.ArrayList();
        
        private System.Collections.Hashtable MyTradeItemsList = new System.Collections.Hashtable();
		
		public System.Collections.Hashtable PartnerTradeItemsList = new System.Collections.Hashtable();
		public System.Collections.ArrayList TradeLogItemList = new System.Collections.ArrayList();


        public bool storageAvailable = false;
        public double Billance = 0;
		
		public string username = "";
		public bool Trading = false;
        public bool SentThanks = false;
		public bool Donating = false;
        public bool Giving = false;
		public bool PutOnSale = false;




        public struct TradeLogItem
		{
			public double price;
			public uint quantity;
			public int KnownItemsSqlID;
			public string action;
		}
		
		public struct SellingItem
		{
			public int PricelistSqlID;
			public int SellingItemsSqlID;
			public int KnownItemsSqlID;
			public bool announce;
			public double pricesale;
			public double pricesalemembers;
		}

		
		public struct WantedItem
		{
			public int PricelistSqlID;
			public int SellingItemsSqlID;
			public int KnownItemsSqlID;
			public bool announce;
            public double pricepurchase;
            public double pricepurchasemembers;
            public int maxquantity;
            public string name;
            public int weight;
        }
		
		public struct TradeItem
		{
			public byte pos;
			public int imageid;
			public uint quantity;
			public string name;
			public int KnownItemsSqlID;
            public double pricepurchase;
            public double pricepurchasemembers;
            public int weight;
        }
		
		public TradeHandler(TCPWrapper MyTCPWrapper, BasicCommunication.MessageParser MyMessageParser, MySqlManager MyMySqlManager, Inventory MyInventory, AdvancedCommunication.ActorHandler MyActorHandler, Logger MyLogger, Storage MyStorage)
		{
			this.TheTCPWrapper = MyTCPWrapper;
			this.TheMessageParser = MyMessageParser;
			this.TheMySqlManager = MyMySqlManager;
			this.TheInventory = MyInventory;
			this.TheActorHandler = MyActorHandler;
			this.TheLogger = MyLogger;
            this.TheStorage = MyStorage;

			
			TradeTimer.Stop();
			TradeTimer.Interval=1000;
			TradeTimer.Elapsed += new System.Timers.ElapsedEventHandler(TradeTimer_Tick );
			
			this.TheTCPWrapper.GotCommand += new TCPWrapper.GotCommandEventHandler(OnGotCommand);
			this.TheMessageParser.Got_TradeRequest += new BasicCommunication.MessageParser.Got_TradeRequest_EventHandler(OnGotTradeRequest);
			this.TheMessageParser.Got_AbortTrade += new BasicCommunication.MessageParser.Got_AbortTrade_EventHandler(OnGotAbortTrade);
			this.TheInventory.GotNewInventoryList += new Inventory.GotNewInventoryListEventHandler(OnGotNewInventoryList);
		}


        public bool AmITrading()
        {
            return Trading;
        }

		private void OnGotNewInventoryList(object sender, Inventory.GotNewInventoryListEventArgs e)
		{
            bool Member = (TheMySqlManager.CheckIfTradeMember(this.username, Settings.botid) == true);
            //Log items got
			foreach (TradeItem MyTradeItem in PartnerTradeItemsList.Values)
			{
				if (MyTradeItem.name!="Gold Coins")
				{
					string action = "";
					if (this.Donating==true)
					{
						action = "received from";
					}
					if (this.PutOnSale==true)
					{
						action = "putonsale";
					}
					if (this.Donating == false && this.PutOnSale==false)
					{
						action = "bought from";
					}
                    if (((!Member && MyTradeItem.pricepurchase == 0) || (!Member && MyTradeItem.pricepurchase == 0)) && action == "bought from")
					{
						action = "received from";
					}
                    AddTrade(MyTradeItem.KnownItemsSqlID, MyTradeItem.pricepurchase, MyTradeItem.quantity, action);
                }
				else
				{
					//Check if money was donated
					if (this.Donating==true)
					{
                        AddTrade(MyTradeItem.KnownItemsSqlID, (Member ? MyTradeItem.pricepurchasemembers : MyTradeItem.pricepurchase), (uint)(MyTradeItem.quantity - System.Convert.ToInt32(System.Math.Ceiling(this.Billance))), "received from");
					}
				}
			}

            //can't we just check the tradeloglist, if we have a trade to log, we log it?
            if (this.TradeLogItemList.Count > 0)
            {
                LogTrade();
            }

            // Check if there was a change in the inventory list
            //if (e.TheInventory.Count!=InventorySnapshopLoging.Count && InventorySnapshopLoging.Count!=0)
            //{
            //    LogTrade();
            //    return;
            //}
			
            //Inventory.inventory_item[] MyInventoryItemsArrayA = (Inventory.inventory_item[])InventorySnapshopLoging.ToArray(typeof(Inventory.inventory_item));
            //Inventory.inventory_item[] MyInventoryItemsArrayB = (Inventory.inventory_item[])e.TheInventory.ToArray(typeof(Inventory.inventory_item));
			
            //for (int i=0;i<MyInventoryItemsArrayA.Length;i++)
            //{
            //    if ((MyInventoryItemsArrayA[i].name != MyInventoryItemsArrayB[i].name) || (MyInventoryItemsArrayA[i].quantity!=MyInventoryItemsArrayB[i].quantity))
            //    {
            //        LogTrade();
            //        return;
            //    }
            //}
            Trading = false;
            return;
		}
		
		private void LogTrade()
		{
            if (SentThanks == false)
            {
                // Log the trade
                foreach (TradeLogItem MyTradeLogItem in TradeLogItemList)
                {
                    this.TheMySqlManager.LogTrade(MyTradeLogItem, this.username, Settings.botid);

                    if (Settings.IsTradeBot == false && !MyTradeLogItem.action.Contains("inv") && Donating == false)
                    {
                        TheMySqlManager.UpdateStorageItem(MyTradeLogItem);
                    }
                }

                this.PartnerTradeItemsList = new System.Collections.Hashtable();
                this.TradeLogItemList = new System.Collections.ArrayList();

                this.InventorySnapshop = TheInventory.GetInventoryList();
                this.InventorySnapshopLoging = (System.Collections.ArrayList)InventorySnapshop.Clone();

                this.Donating = false;
                this.PutOnSale = false;
                TheTCPWrapper.Send(CommandCreator.SEND_PM(this.username, "Thank you for using my services!"));
                TheLogger.Log("Trade was successful!");
                SentThanks = true;
                this.username = "";
//              TheTCPWrapper.Send(CommandCreator.SIT_DOWN(false));
            }
		}
		
		public void AddTrade(int KnownItemsSqlID, double price, uint quantity, string action)
		{
            TradeLogItem MyTradeLogItem;
			MyTradeLogItem.action = action;
			MyTradeLogItem.quantity = quantity;
			MyTradeLogItem.price = price;
			MyTradeLogItem.KnownItemsSqlID = KnownItemsSqlID;
			TradeLogItemList.Add(MyTradeLogItem);
            TheLogger.Debug("AddTrade " + KnownItemsSqlID.ToString() + "\n");
		}

        private void OnGotTradeRequest(object sender, BasicCommunication.MessageParser.Got_TradeRequest_EventArgs e, bool junk)
        {
            string TradePartnerUsername = e.username;
            Int16 TradePartnerUserID = TheActorHandler.GetUserIDFromname(TradePartnerUsername);
            TheTCPWrapper.Send(CommandCreator.TRADE_WITH(TradePartnerUserID));
        }
        
        private void OnGotTradeRequest(object sender, BasicCommunication.MessageParser.Got_TradeRequest_EventArgs e)
        {
            string TempPartnerUsername = e.username;
            Int16 TempPartnerUserID = TheActorHandler.GetUserIDFromname(TempPartnerUsername);
            if (Trading == true)
            {
                TheTCPWrapper.Send(CommandCreator.SEND_PM(TempPartnerUsername, "Sorry, I am busy. Please try the #retrade in a few seconds!"));
                return;
            }
            string TradePartnerUsername = e.username;
			Int16 TradePartnerUserID = TheActorHandler.GetUserIDFromname(TradePartnerUsername);
            int playerRank = TheMySqlManager.GetUserRank(e.username, Settings.botid);
            int buyCommandRank = TheMySqlManager.GetCommandRank("#buy", Settings.botid);
            int guildRank = TheMySqlManager.CheckIfBannedGuild(e.username, Settings.botid);

            if ( playerRank < buyCommandRank )
            {
                TheTCPWrapper.Send(CommandCreator.TRADE_WITH(TradePartnerUserID));
                TheTCPWrapper.Send(CommandCreator.EXIT_TRADE());
                if (playerRank < 0)
                {
                    TheTCPWrapper.Send(CommandCreator.SEND_PM(TradePartnerUsername, "I don't trade with players that are banned from using my services"));
                }
                else
                {
                    TheTCPWrapper.Send(CommandCreator.SEND_PM(e.username, "Sorry, you are not authorized to trade with me!"));
                }
                return;
            }


//            if (guildRank < 0 && (playerRank <= buyCommandRank))
            if (guildRank < 0 && ((playerRank <= buyCommandRank)||playerRank == 0))
            {
                TheTCPWrapper.Send(CommandCreator.TRADE_WITH(TradePartnerUserID));
                TheTCPWrapper.Send(CommandCreator.EXIT_TRADE());
                if (guildRank < 0)
                {
                    TheTCPWrapper.Send(CommandCreator.SEND_PM(TradePartnerUsername, "I don't trade with guilds that are banned from using my services"));
                }
                return;
            }

			
			// Check if I am not busy (e.g. getting inventory item names)
			if (TheInventory.GettingInventoryItems==true)
			{
				TheTCPWrapper.Send(CommandCreator.TRADE_WITH(TradePartnerUserID));
				TheTCPWrapper.Send(CommandCreator.EXIT_TRADE());
				TheTCPWrapper.Send(CommandCreator.SEND_PM(TradePartnerUsername,"Sorry, I am busy. Please try again in a few seconds!"));
                return;
			}

            // Check if I am a trade bot or a storage bot
            //ok, if this person isn't in range at all, we don't wanna try to trade with them
            if (TheActorHandler.ActorsHashTable.Contains(TheActorHandler.GetUserIDFromname(TradePartnerUsername)) == false)
            {
                TheTCPWrapper.Send(CommandCreator.SEND_PM(TradePartnerUsername, "Trying to trade out of range is a no no! please don't do it :P"));
                TheTCPWrapper.Send(CommandCreator.EXIT_TRADE());
                return;
            }
            if (Settings.IsTradeBot == false)
            {
                TheTCPWrapper.Send(CommandCreator.SEND_PM(TradePartnerUsername, "Hello " + TradePartnerUsername + ", I am a storage bot"));
                TheTCPWrapper.Send(CommandCreator.SEND_PM(TradePartnerUsername, "To give me an item, just drop it in the trade window"));
                TheTCPWrapper.Send(CommandCreator.SEND_PM(TradePartnerUsername, "To get an item, use the give command eg give 1 pickaxe"));
            }
            else
            {

                TheTCPWrapper.Send(CommandCreator.SEND_PM(TradePartnerUsername, "Hello " + TradePartnerUsername + ", I am a trade bot"));
                TheTCPWrapper.Send(CommandCreator.SEND_PM(TradePartnerUsername, "To sell me an item, just drop it in the trade window"));
                TheTCPWrapper.Send(CommandCreator.SEND_PM(TradePartnerUsername, "To buy an item, use the BUY command eg buy 1 pickaxe"));
            }
            // Reset all variables for fresh trade
			this.username = TradePartnerUsername;
			this.GettingTradListItemnameID = 255;
			this.TradeLogItemList.Clear();
			this.AcceptStateMe = 0;
			this.AcceptStatePartner = 0;
			this.Billance = 0;
            SentThanks = false;
			this.InventorySnapshop = TheInventory.GetInventoryList();
//            this.StorageSnapshot = TheStorage.GetStorageList();
			this.InventorySnapshopLoging = (System.Collections.ArrayList)InventorySnapshop.Clone();
			
			this.MyMoneyAmount = TheInventory.GetMoneyAmount();
			this.MyMoneySlotID = TheInventory.GetMoneySlotID();
			this.MyMoneyOnTrade = 0;
			this.MyMoneyOnTradeSlotID = 0;
			
			//this.Trading = false;
			//this.Donating = false;
            if (Settings.IsTradeBot == false)
            {
                this.Donating = true;
            }
            this.PutOnSale = false;
            //TheTCPWrapper.Send(CommandCreator.SIT_DOWN(true));
			// Start the counter for Trade-Timeout
			if (Settings.TradeTimeOut!=0)
			{
				TradeTimeElapsed = 0;
				TradeTimer.Start();
			}
			
			//Reset the TradeItemsLists
			MyTradeItemsList = new System.Collections.Hashtable();
			PartnerTradeItemsList = new System.Collections.Hashtable();
			
			// Accept the trade
			TheTCPWrapper.Send(CommandCreator.TRADE_WITH(TradePartnerUserID));
            Trading = true;
        }
		
		private void OnGotAbortTrade(object sender, System.EventArgs e)
		{
            TradeTimer.Stop();
            TradeTimer.Stop();
            TradeTimeElapsed = 0;
            if (TheInventory.GettingInventoryItems == false && Trading == true)
            {
                username = "";
                this.TradeLogItemList.Clear();
                TheTCPWrapper.Send(CommandCreator.SEND_MY_INVENTORY());
//                TheInventory.GettingInventoryItems = true;
//                Trading = false;
            }
            SentThanks = true;
            Trading = false;
            Donating = false;
            //            TheStorage.gettingStorageItems = false;
            //TheTCPWrapper.Send(CommandCreator.REJECT_TRADE());
        }
		
		private void TradeTimer_Tick(object sender,System.Timers.ElapsedEventArgs eArgs)
		{
			TradeTimeElapsed++;
			
			// Check if we have reached the Trade-Timeout
			if (TradeTimeElapsed>Settings.TradeTimeOut && Settings.TradeTimeOut!=0)
			{
				TheTCPWrapper.Send(CommandCreator.SEND_PM(username,"Sorry, your trade time is over. You had " + Settings.TradeTimeOut.ToString() + " seconds to do the trade. Please try again!"));
				TheTCPWrapper.Send(CommandCreator.EXIT_TRADE());
				TradeTimer.Stop();
				TradeTimeElapsed = 0;
				//Trading = false;
				username = "";
                SentThanks = true;
			}
		}
		
		private void OnGotCommand(object sender, TCPWrapper.GotCommandEventArgs e)
		{
            if (e.CommandBuffer[0] == 35) // GET_TRADE_OBJECT
			{
                GET_TRADE_OBJECT(e.CommandBuffer);
				return;
			}
			if (e.CommandBuffer[0] == 36)
			{
				GET_TRADE_ACCEPT(e.CommandBuffer);
				return;
			}
			if (e.CommandBuffer[0] == 37)
			{
				GET_TRADE_REJECT(e.CommandBuffer);
				return;
			}
            if (e.CommandBuffer[0] == 38)
            {
                GET_TRADE_ABORT(e.CommandBuffer);
                return;
            }
            if (e.CommandBuffer[0] == 39)
			{
				REMOVE_TRADE_OBJECT(e.CommandBuffer);
				return;
			}
			if (e.CommandBuffer[0] == 20)
			{
				INVENTORY_ITEM_TEXT(e.CommandBuffer);
				return;
			}
            // 40 = GET_YOUR_TRADE_OBJECTS, sent whenever a trade is initiated
            if (e.CommandBuffer[0] == 40) //GET_YOUR_TRADE_OBJECTS
            {
                GET_YOUR_TRADE_OBJECTS(e.CommandBuffer);
                return;
            }
            if (e.CommandBuffer[0] == 41) //GET_TRADE_PARTNER_name
            {
                int i,storagetrade;
                i = System.BitConverter.ToInt16(e.CommandBuffer, 1) - 2;
                storagetrade = System.BitConverter.ToInt16(e.CommandBuffer, 3);
                string name = System.Text.Encoding.ASCII.GetString(e.CommandBuffer, 4, i);
                return;
            }
            if (e.CommandBuffer[0] == 67) // STORAGE_LIST
            {
                STORAGE_LIST(e.CommandBuffer);
                return;
            }
            
            if (e.CommandBuffer[0] == 68) // STORAGE_ITEMS (per category)
            {
                STORAGE_ITEMS(e.CommandBuffer);
                return;
            }
        
            if (e.CommandBuffer[0] == 69) // STORAGE_TEXT
            {
                STORAGE_TEXT(e.CommandBuffer);
                return;
            }
        }

        private void GET_YOUR_TRADE_OBJECTS(byte[] data)
        {
            int itemCount = data[3];
            return;
        }

        private void STORAGE_TEXT(byte[] data)
        {
            if (Trading == false || TheInventory.GettingInventoryItems == true)
                return;

            string TempItemDescription;

            TempItemDescription = System.Text.ASCIIEncoding.ASCII.GetString(data, 4, data.Length - 4).Trim();
            TheStorage.UpdateText(TempItemDescription);
            this.StorageSnapshot = TheStorage.GetStorageList();
            return;
        }

        private void STORAGE_ITEMS(byte[] data)
        {
            if (Trading == false || TheInventory.GettingInventoryItems == true)
                return;
            uint item_count = data[3]; // should be in this byte but isn't yet :P
            UInt16 data_length = System.BitConverter.ToUInt16(data,1);
            data_length += 2;
            uint category_num = data[4];
            byte pos;
            int imageid;
            uint quantity;
            Storage.StorageItem MyStorageItem = new Storage.StorageItem();
            // so, we're calculating the number of items with the size of the packet
            item_count = (uint)(data_length - 5) / 8;
            if (item_count > 0)
            {
                for (int i = 0; i < item_count;i++)
                {
                    imageid = System.BitConverter.ToUInt16(data, i * 8 + 5);
                    quantity = System.BitConverter.ToUInt32(data, i * 8 + 5 + 2);
                    pos = data[i * 8 + 5 + 6];
                    MyStorageItem.imageid = imageid;
                    MyStorageItem.pos = pos;
                    MyStorageItem.quantity = quantity;
                    MyStorageItem.name = "";
                    MyStorageItem.category_num = category_num;
                    TheStorage.AddItem(MyStorageItem);
                    TheTCPWrapper.Send(CommandCreator.LOOK_AT_STORAGE_ITEM((byte)pos));
                }
            }
            return;
        }

        private void STORAGE_LIST(byte[] data)
        {
            int total_categories = data[3];
            int category_number = 0;
            int stringsize = 1;
            string category_name = "";

            storageAvailable = true;
            TheStorage.ClearCategories();
            Storage.StorageCategory MyStorageCategory = new Storage.StorageCategory();
            TheStorage.ClearList();

            // loop through the total categories getting each one and its id
            for (int i = 0; i < total_categories; i++)
            {
                category_number = data[i + stringsize + 3];
                category_name = "";
                // the names are seperated by a 0x00, so read each byte until we find it
                while (data[i + stringsize + 3] != 0x00)
                {
                    stringsize++;
                    if (data[i + stringsize + 3] > 32 && data[i + stringsize + 3] < 126)
                    {
                        category_name += System.Text.ASCIIEncoding.ASCII.GetString(data, i + 3 + stringsize, 1);
                    }
                }
                // add the category to the array of categories
                MyStorageCategory.name = category_name;
                MyStorageCategory.num = category_number;
                TheStorage.AddCategory(category_name, category_number);
                TheTCPWrapper.Send(CommandCreator.GET_STORAGE_CATEGORY((byte)category_number));
            }
            TheStorage.AddCategory("Temporarily Unknown", -1);

        }
		private void GET_TRADE_ACCEPT(byte [] buffer)
		{
			//int TheBillance = 0;
			
			if (buffer[3] == 0)
			{
				AcceptStateMe=1;
				TheLogger.Debug("RX: ME: GET_TRADE_ACCEPT\n");
				return;
			}
			
			TheLogger.Debug("RX: PARTNER: GET_TRADE_ACCEPT\n");

            if (PartnerTradeItemsList.Count == 0 && TradeLogItemList.Count == 0)
            {
                TheTCPWrapper.Send(CommandCreator.EXIT_TRADE());
                TheLogger.Debug("TX: EXIT_TRADE\n");
            }
            if (System.Math.Floor(this.Billance) == this.MyMoneyOnTrade)
			{
				if (AcceptStatePartner==1 && AcceptStateMe == 1)
				{
					TradeTimer.Stop();
					TradeTimeElapsed = 0;
					TheTCPWrapper.Send(CommandCreator.ACCEPT_TRADE_ENTIRE( storageAvailable ));
					TheLogger.Debug("TX: ACCEPT_TRADE_ENTIRE\n");
                }
				else
				{
					AcceptStatePartner=1;
					TheTCPWrapper.Send(CommandCreator.ACCEPT_TRADE());
					TheLogger.Debug("TX: ACCEPT_TRADE\n");
				}
            }
			else
			{
				//AcceptStatePartner=1;
                TheTCPWrapper.Send(CommandCreator.SEND_PM(username, "Sorry, I can't accept this trade!"));
                TheTCPWrapper.Send(CommandCreator.EXIT_TRADE());
				TheLogger.Debug("TX: EXIT_TRADE\n");
			}
		}
		
		private void GET_TRADE_REJECT(byte [] buffer)
		{
			
			if (buffer[3] == 0)
			{
				TheLogger.Debug("RX : ME: GET_TRADE_REJECT\n");
				AcceptStateMe = 0;
			}
			else
			{
				TheLogger.Debug("RX : PARTNER: GET_TRADE_REJECT\n");
				AcceptStatePartner = 0;
//				TheTCPWrapper.Send(CommandCreator.REJECT_TRADE());
			}
		}

        private void GET_TRADE_ABORT(byte[] buffer)
        {
            //not sure what to do here
        }
		
		public void ChangeBillance(double Billance)
		{
			// Trying to fix floating point operations
			Billance = Billance * 1000;
			Billance = System.Math.Round(Billance);
			Billance = Billance / 1000;
			
			this.Billance = this.Billance * 1000;
			this.Billance = System.Math.Round(this.Billance);
			this.Billance = this.Billance / 1000;
			
			this.Billance += Billance;
			
			this.Billance = this.Billance * 1000;
			this.Billance = System.Math.Round(this.Billance);
			this.Billance = this.Billance / 1000;
			
			int RoundedBillance = System.Convert.ToInt32(System.Math.Floor(this.Billance));
//            Console.WriteLine(RoundedBillance);
			
			if (RoundedBillance>this.MyMoneyOnTrade)
			{
				this.MyMoneyOnTrade += PutItemsOnTrade(1,(System.Convert.ToUInt32(RoundedBillance-this.MyMoneyOnTrade)));
				if (this.MyMoneyOnTrade<RoundedBillance)
				{
					TheTCPWrapper.Send(CommandCreator.SEND_PM(username,"Sorry, I don't have enough change!"));
				}
			}
			
			if (this.MyMoneyOnTrade>RoundedBillance && this.MyMoneyOnTrade>0)
			{
				if (RoundedBillance<=0)
				{
					// Update the InventorySnapshop
					Inventory.inventory_item MyInventoryItem = (Inventory.inventory_item)InventorySnapshop[this.MyMoneySlotID];
					MyInventoryItem.quantity += this.MyMoneyOnTrade;
					InventorySnapshop[this.MyMoneySlotID] = MyInventoryItem;
					
					// Remove the items from trade
					TheTCPWrapper.Send(CommandCreator.REMOVE_OBJECT_FROM_TRADE(System.Convert.ToByte(this.MyMoneyOnTradeSlotID),this.MyMoneyOnTrade));
					this.MyMoneyOnTrade = 0;
				}
				else
				{
					// Update the InventorySnapshop
					Inventory.inventory_item MyInventoryItem = (Inventory.inventory_item)InventorySnapshop[this.MyMoneySlotID];
					MyInventoryItem.quantity += System.Convert.ToUInt32((this.MyMoneyOnTrade-RoundedBillance));
					InventorySnapshop[this.MyMoneySlotID] = MyInventoryItem;
					
					// Remove the items from trade
					TheTCPWrapper.Send(CommandCreator.REMOVE_OBJECT_FROM_TRADE(System.Convert.ToByte(this.MyMoneyOnTradeSlotID),System.Convert.ToUInt32((this.MyMoneyOnTrade-RoundedBillance))));
					this.MyMoneyOnTrade -= System.Convert.ToUInt32((this.MyMoneyOnTrade-RoundedBillance));
				}
			}
			
			if (RoundedBillance<this.MyMoneyOnTrade)
			{
				TheTCPWrapper.Send(CommandCreator.SEND_PM(username,"You owe me " + (-RoundedBillance).ToString() + " gc!"));
			}
			
			TheLogger.Debug("Billance:" + this.Billance.ToString() + "\n");
			TheLogger.Debug("RoundedBillance:" + RoundedBillance.ToString() + "\n");
		}

        public uint PutItemsOnTrade(int SQLID, uint quantity)
        { 
            return PutItemsOnTrade( SQLID, quantity, false);
        }
        public uint PutItemsOnTrade(int SQLID, uint quantity, bool fromInventory)
		{
            uint QuantityPutOnTrade = 0;
            bool itemFound = false;
            uint reservedAmount = TheMySqlManager.ReservedAmount(SQLID);
            uint reservedAmountForUser = TheMySqlManager.ReservedAmountForUser(SQLID, username);

            if (Settings.IsTradeBot == true || fromInventory == true)
            {
                for (int i = 0; i < InventorySnapshop.Count; i++)
                {
                    Inventory.inventory_item MyInventoryItem = (Inventory.inventory_item)InventorySnapshop[i];

                    if (MyInventoryItem.SqlID == SQLID && MyInventoryItem.pos < 36)
                    {
                        if (MyInventoryItem.is_stackable == true)
                        {
                            if (MyInventoryItem.quantity > (reservedAmount + quantity))
                            {
                                QuantityPutOnTrade += (uint)(quantity);
                                TheTCPWrapper.Send(CommandCreator.PUT_OBJECT_ON_TRADE(MyInventoryItem.pos, (uint)(QuantityPutOnTrade), fromInventory));
                                if ((MyInventoryItem.quantity - (uint)QuantityPutOnTrade) < 0)
                                {
                                    MyInventoryItem.quantity = 0;
                                }
                                else
                                {
                                    MyInventoryItem.quantity -= (uint)QuantityPutOnTrade;
                                }
                                InventorySnapshop[i] = MyInventoryItem;
                            }
                            else
                            {
                                int qtyAvailableForTrade = (int)(MyInventoryItem.quantity - (reservedAmount - reservedAmountForUser));
                                if (qtyAvailableForTrade > 0)
                                {
                                    if (qtyAvailableForTrade < MyInventoryItem.quantity)
                                    {
                                        if (qtyAvailableForTrade > quantity)
                                        {
                                            QuantityPutOnTrade = quantity;
                                        }
                                        else
                                        {
                                            QuantityPutOnTrade = (uint)qtyAvailableForTrade;
                                        }
                                    }
                                    else
                                    {
                                        if (qtyAvailableForTrade > quantity)
                                        {
                                            QuantityPutOnTrade = quantity;
                                        }
                                        else
                                        {
                                            QuantityPutOnTrade = (uint)qtyAvailableForTrade;
                                        }
                                    }
                                }
                                else
                                {
                                    QuantityPutOnTrade = 0;
                                }
//                                QuantityPutOnTrade += (uint)(MyInventoryItem.quantity - reservedAmount);
                                TheTCPWrapper.Send(CommandCreator.PUT_OBJECT_ON_TRADE(MyInventoryItem.pos, (uint)QuantityPutOnTrade, fromInventory));
                                MyInventoryItem.quantity -= (uint)QuantityPutOnTrade;
                                InventorySnapshop[i] = MyInventoryItem;
                            }
                        }
                        else
                        {
                            if (reservedAmount > 0)
                            {
                                reservedAmount--;
                            }
                            else
                            {
                                QuantityPutOnTrade += (uint)MyInventoryItem.quantity;
                                TheTCPWrapper.Send(CommandCreator.PUT_OBJECT_ON_TRADE(MyInventoryItem.pos, MyInventoryItem.quantity, fromInventory));
                                MyInventoryItem.quantity = 0;
                                InventorySnapshop[i] = MyInventoryItem;
                            }
                        }

                        if (QuantityPutOnTrade >= quantity)
                        {
                            break;
                        }
                    }
                }
            }
            else
            {
                int total_items = StorageSnapshot.Count;
                for (int i = 0; i < total_items; i++)
                {
                    Storage.StorageItem MyStorageItem = (Storage.StorageItem)StorageSnapshot[i];
                    if (MyStorageItem.knownItemsID == SQLID && itemFound == false)
                        {
                            itemFound = true;
                            if (MyStorageItem.quantity <= (quantity - QuantityPutOnTrade))
                                {
                                    TheTCPWrapper.Send(CommandCreator.PUT_OBJECT_ON_TRADE(MyStorageItem.pos, MyStorageItem.quantity, false));
                                    QuantityPutOnTrade += (uint)MyStorageItem.quantity;
                                    MyStorageItem.quantity = 0;
                                    StorageSnapshot[i] = MyStorageItem;
                                }
                            else
                                {
                                    TheTCPWrapper.Send(CommandCreator.PUT_OBJECT_ON_TRADE(MyStorageItem.pos, (uint)(quantity - QuantityPutOnTrade)));
                                    QuantityPutOnTrade += (uint)quantity;
                                    MyStorageItem.quantity -= (uint)quantity;
                                    StorageSnapshot[i] = MyStorageItem;
                                }
                        }
                }

            }
//            Console.WriteLine("qty put on trade: " + QuantityPutOnTrade);
            return (uint)QuantityPutOnTrade;
        }
		
		private void GET_TRADE_OBJECT(byte [] buffer)
		{
			TheLogger.Debug("GET_TRADE_OBJECT\n");
			
			// buffer[11]==1 --> New trade object on the trade partner side
			// buffer[11]==0 --> New trade object on my side
			if (buffer[11]==1)
			{
				byte pos = buffer[10];

                //here here
                TradeItem MyTradeItem;
				if (PartnerTradeItemsList.Contains(pos)) // is this item already in the trade window?
				{
//                    if (Settings.IsTradeBot == true)
                    {
                        MyTradeItem = (TradeItem)PartnerTradeItemsList[pos];
                        MyTradeItem.quantity += System.BitConverter.ToUInt32(buffer, 5);
                        PartnerTradeItemsList[pos] = MyTradeItem;
                        if (MyTradeItem.name != "")
                        {
                            CheckBuyingItems(MyTradeItem, System.BitConverter.ToUInt32(buffer, 5), MyTradeItem.quantity);
                        }
                    }
				}
				else
				{
                    MyTradeItem = new TradeItem();
					MyTradeItem.pos = pos;
					MyTradeItem.imageid = System.BitConverter.ToInt16(buffer,3);
                    if (MyTradeItem.imageid == 3 && Billance == 0 && Donating == false)
                    {
                        TheLogger.Debug("MyWantedItemList.Contains complete\nItem not wanted for purchase\n");
                        TheTCPWrapper.Send(CommandCreator.SEND_PM(this.username, "Sorry, but I am not buying Gold Coins."));
                        TheTCPWrapper.Send(CommandCreator.EXIT_TRADE());
                        return;
                    }
                    MyTradeItem.quantity = System.BitConverter.ToUInt32(buffer, 5);
					MyTradeItem.name="";
                    MyTradeItem.pricepurchase = 0;
                    MyTradeItem.pricepurchasemembers = 0;
					
					MyTradeItem.KnownItemsSqlID=-1;
                    //PartnerTradeItemsList.Add(pos, MyTradeItem);
                    PartnerTradeItemsList.Add(pos,MyTradeItem);
					
					GettingTradListItemnameID = pos;
					
					TheLogger.Debug("Got new Item at pos:" + pos.ToString()+"\n");
                    TheTCPWrapper.Send(CommandCreator.LOOK_AT_TRADE_ITEM(pos, true));
                }
            }
			
			// Check the slot of my own money - old comment
            // See if this is the money slot or not, if it is, remember it.
			if (buffer[11]==0)
			{
				byte pos = buffer[10];
				int imageid = System.BitConverter.ToInt16(buffer,3);
				
				if (imageid==3)
				{
					this.MyMoneyOnTradeSlotID = pos;
				}
			}
			
            // see if they put money in to pay for the trade, if so, adjust the balance.
			if (buffer[11]==1 && System.BitConverter.ToUInt16(buffer,3)==3)
			{
				if (this.Donating==false)
				{
					ChangeBillance((int)System.BitConverter.ToUInt32(buffer,5));
				}
			}
		}
		
		private void REMOVE_TRADE_OBJECT(byte [] buffer)
		{						
			if (buffer[8]==1)
			{
				byte pos = buffer[7];
				UInt32 quantity = System.BitConverter.ToUInt32(buffer,3);
				TheLogger.Debug("REMOVE_TRADE_OBJECT pos:" + pos.ToString() + " quantity:" + quantity.ToString() + "\n");
				
				if (PartnerTradeItemsList.Contains(pos))
				{
					TradeItem MyTradeItem = (TradeItem)PartnerTradeItemsList[pos];
					
					if (MyTradeItem.quantity-quantity<1)
					{
                        if (Settings.IsTradeBot == true)
                        {
                            if (Donating == false)
                            {
                                if (MyTradeItem.name == "Gold Coins")
                                {
                                    ChangeBillance(-(int)quantity);

                                }
                                else
                                {
                                    CheckBuyingItems(MyTradeItem, -(quantity), -(quantity));
                                }
                            }
                        }
						PartnerTradeItemsList.Remove(pos);
					}
					else
					{
                        if (Settings.IsTradeBot == true)
                        {
                            if (Donating == false)
                            {
                                if (MyTradeItem.name == "Gold Coins")
                                {
                                    ChangeBillance(-(int)quantity);
                                }
                                else
                                {
                                    CheckBuyingItems(MyTradeItem, -(quantity), -(quantity));
                                }
                            }
                        }
						MyTradeItem.quantity -= quantity;
						PartnerTradeItemsList[pos] = MyTradeItem;
					}
				}
				else
				{
					TheLogger.ErrorLog("Error while REMOVE_TRADE_OBJECT - PartnerTradeItemsList does not contain pos");
				}
			}
		}
		
		private void INVENTORY_ITEM_TEXT (byte[] data)
		{

            if (Trading == false || TheInventory.GettingInventoryItems == true)
                return;
            //if getting storage items still, pause here...
            int i=0;
			string ItemDescription = "";
			string TempItemDescription = "";
			
			TempItemDescription=System.Text.ASCIIEncoding.ASCII.GetString(data,4,data.Length-4).Trim();
            // remove bad some chars (eg color tags)
            TempItemDescription = TempItemDescription.Replace((char)10, ' ');
			
            TheLogger.Debug("Beginning FOR loop (1)\n");
			for (i=0;i<TempItemDescription.Length;i++)
			{
				if (!(TempItemDescription[i]<32 || TempItemDescription[i]>126))
				{
					ItemDescription = ItemDescription+TempItemDescription[i];
				}
			}
            TheLogger.Debug("FOR loop (1) completed\n");
            TradeItem MyTradeItem = new TradeItem();
            MyTradeItem.pos = 0;

            // Get all the keys in the hashtable and sort them
            ArrayList keys = new ArrayList(PartnerTradeItemsList.Keys);
            keys.Sort();

            foreach (object obj in keys)
            {
                MyTradeItem = (TradeItem)PartnerTradeItemsList[obj];
                if (MyTradeItem.name == "")
                {
                    break;
                }
            }
            TheLogger.Debug("Beginning TRIM(1)\n");
            ItemDescription = ItemDescription.Trim();
            MyTradeItem.name = ItemDescription;
            MyTradeItem.name = MyTradeItem.name.Replace((char)10, ' ');
            MyTradeItem.name = MyTradeItem.name.Substring(0, MyTradeItem.name.IndexOf("Weight:"));
            MyTradeItem.name = MyTradeItem.name.Trim();
            PartnerTradeItemsList[MyTradeItem.pos] = MyTradeItem;

            if (Settings.IsTradeBot == true)
            {
                MyTradeItem.pricepurchase = CheckBuyingItems(MyTradeItem, MyTradeItem.quantity, MyTradeItem.quantity);
            }
            else
            {
                MyTradeItem.pricepurchase = 0;
            }
            MyTradeItem.weight = int.Parse(ItemDescription.Substring(ItemDescription.IndexOf("Weight:") + 8, ItemDescription.Length - (ItemDescription.IndexOf("Weight:") + 8 + 4)));
            TradeItem MyTempTradeItem = new TradeItem();
            MyTempTradeItem = MyTradeItem;
            MyTradeItem.KnownItemsSqlID = TheMySqlManager.GetKnownItemsSQLID(MyTempTradeItem);
            PartnerTradeItemsList[MyTradeItem.pos] = MyTradeItem;

            //double check if this was needed or not..... testing
            Inventory.inventory_item MyInventoryItem = new Inventory.inventory_item();
            MyInventoryItem.name = MyTradeItem.name;
            MyInventoryItem.imageid = MyTradeItem.imageid;
            MyInventoryItem.name = MyTradeItem.name;
            MyInventoryItem.is_resource = false;
            MyInventoryItem.is_reagent = false;
            MyInventoryItem.is_stackable = false;
            MyInventoryItem.use_with_inventory = false;
            MyInventoryItem.description = "";
            MyInventoryItem.weight = MyTradeItem.weight;
            TheMySqlManager.updateknownitems(MyInventoryItem, MyTradeItem.KnownItemsSqlID);

		}
		
		private double CheckBuyingItems(TradeItem MyTradeItem, long quantity,long TotalQuantity)
		{
            int count;
            bool Member = (TheMySqlManager.CheckIfTradeMember(this.username, Settings.botid) == true);
            int foundSQLID = -1;
            //loop through the wanted list to see if we want it...
            foreach (WantedItem MyWantedItem in TheMySqlManager.GetWantedItemList(0).Values)
            {
                if (MyTradeItem.name.ToLower() == MyWantedItem.name.ToLower())
                {
                    foundSQLID = MyWantedItem.KnownItemsSqlID;
                    break;
                }
            }
            MyTradeItem.KnownItemsSqlID = foundSQLID;

            TheLogger.Debug("CheckBuyingItems(1) Entered\n");
            if (this.Donating == true && quantity > 0)
			{
                TheLogger.Debug("Donating\n");
                return 0;
			}
			
			if (this.PutOnSale==true && quantity>0)
			{
                TheLogger.Debug("Putonsale\n");
                return 0;
			}

            TheLogger.Debug("Passed 2 IF(), entering third: MyTradeItem.imageid = " + MyTradeItem.imageid.ToString() + "\n");
            if (MyTradeItem.name != "Gold Coins")
            {
                System.Collections.Hashtable MyWantedItemList = TheMySqlManager.GetWantedItemList(0);
                TheLogger.Debug("Beginning MyWantedItemList.Contains\n");
                if (MyWantedItemList.Contains(MyTradeItem.KnownItemsSqlID))
                {
                    TheLogger.Debug("MyWantedItemList.Contains IF() passed\nBeginning WantedItem\n");
                    WantedItem MyWantedItem = (WantedItem)MyWantedItemList[MyTradeItem.KnownItemsSqlID];
                    TheLogger.Debug("WantedItem complete\nSending PM");
                    if (MyWantedItem.maxquantity > 0)
                    {
                        count = System.Convert.ToInt32(TotalQuantity);
                        TheLogger.Debug("Max " + MyWantedItem.maxquantity.ToString() + "count " + count.ToString() + "\n");
                        if (  TheInventory.HaveItem(MyTradeItem.name) != 0)
                        {
                            if (TheInventory.Quantity(MyTradeItem.name) > MyWantedItem.maxquantity)
                            {
                                TheTCPWrapper.Send(CommandCreator.SEND_PM(this.username, "I am already carrying more than my allowed quantity of " + MyTradeItem.name + "."));
                                AcceptStateMe = 0;
                                TheTCPWrapper.Send(CommandCreator.EXIT_TRADE());
                                return 0;
                            }
                            count += TheInventory.Quantity(MyTradeItem.name);
                        }
                        if (MyWantedItem.maxquantity < count)
                        {
                            TheLogger.Debug("Too many\n");
                            TheTCPWrapper.Send(CommandCreator.SEND_PM(this.username, "I am only buying up to " + ( MyWantedItem.maxquantity - TheInventory.Quantity(MyTradeItem.name) )+ " " + MyTradeItem.name + "."));
                            AcceptStateMe = 0;
                            TheTCPWrapper.Send(CommandCreator.EXIT_TRADE());
                            return 0;
                        }
                    }
                    if (quantity > 0)
                    {
                        TheTCPWrapper.Send(CommandCreator.SEND_PM(this.username, "I am buying " + MyTradeItem.name + " for " + (Member ? MyWantedItem.pricepurchasemembers.ToString() : MyWantedItem.pricepurchase.ToString()) + " gc each."));
                    }
                    TheLogger.Debug("PM sent\nBegin ChangeBillance\n");
                    ChangeBillance((Member ? MyWantedItem.pricepurchasemembers : MyWantedItem.pricepurchase) * quantity);
                    TheLogger.Debug("ChangeBillance complete\n");
                    TheLogger.Debug("MyWantedItemList.Contains complete\n");
                    return (Member ? MyWantedItem.pricepurchasemembers : MyWantedItem.pricepurchase);
                }
                TheLogger.Debug("MyWantedItemList.Contains complete\nItem not wanted for purchase\n");
                TheTCPWrapper.Send(CommandCreator.SEND_PM(this.username, "Sorry, but I am not buying " + MyTradeItem.name + "."));
                TheTCPWrapper.Send(CommandCreator.EXIT_TRADE());
            }
			
			return 0;
		}
	}
}
